#ifndef __pixel_H__
#define __pixel_H__

#include "rendPlatform.hpp"

#if		REND_TARGET_ENDIANNESS == 0

	#error known endianness mandatory

#endif

namespace rend
{

////////////////////////////////////////////////////////////////////////////////////////////////////
// remark on usage
//
// the following pixel classes are NOT color manipulators; they are access abstractors and serve to
// provide efficient read and write access to individual pixels of various formats.
//
// the integral type of a pixel is an integer type of size greater or equal to the sum of all bits
// of all channels of the respective format. therefore, array-style indexation and 'sizeof' are not
// recommended operations on pixel objects; instead, use the 'packed size' of a pixel type, together
// with byte pointer arithmetic when indexation is needed.
//
// the default conversions between pixels of different channel counts adhere to these conventions:
// when the source has more channels than the destination the superfluous channels are discarded;
// conversely, destination channels unaccounted for in the source are set to logical one.
////////////////////////////////////////////////////////////////////////////////////////////////////

template < typename INTEGRAL_T,
		   unsigned NUMBITS_C1_T,
		   unsigned NUMBITS_C0_T >
class Pixel2;

template < typename INTEGRAL_T,
		   unsigned NUMBITS_C2_T,
		   unsigned NUMBITS_C1_T,
		   unsigned NUMBITS_C0_T >
class Pixel3;

template < typename INTEGRAL_T,
		   unsigned NUMBITS_C3_T,
		   unsigned NUMBITS_C2_T,
		   unsigned NUMBITS_C1_T,
		   unsigned NUMBITS_C0_T >
class Pixel4;

////////////////////////////////////////////////////////////////////////////////////////////////////
// class Pixel2
////////////////////////////////////////////////////////////////////////////////////////////////////

template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
class Pixel2
{
	INTEGRAL_T			m;

public:

	enum
	{
		NUMBITS_C1		= NUMBITS_C1_T,
		NUMBITS_C0		= NUMBITS_C0_T,
		NUMBITS			= NUMBITS_C1_T + NUMBITS_C0_T,

		NUMBYTES		= NUMBITS + 7 >> 3,

		MASKBITS_C1		= (1 << NUMBITS_C1_T) - 1,
		MASKBITS_C0		= (1 << NUMBITS_C0_T) - 1,

#if		REND_TARGET_ENDIANNESS == __TARGET_ENDIANNESS_BIG

		SHIFTBITS		= (sizeof(INTEGRAL_T) << 3) - NUMBITS,

		SHIFTBITS_C1	= SHIFTBITS,
		SHIFTBITS_C0	= SHIFTBITS + NUMBITS_C1,
#else

		SHIFTBITS		= 0,

		SHIFTBITS_C1	= SHIFTBITS + NUMBITS_C0,
		SHIFTBITS_C0	= SHIFTBITS,
#endif

		MASK			= (1 << NUMBITS) - 1 << SHIFTBITS,

		FORCE_INTEGRAL	= (INTEGRAL_T) -1
	};

	Pixel2() {}

	INTEGRAL_T			get_c1() const { return m >> SHIFTBITS_C1 & MASKBITS_C1; }
	INTEGRAL_T			get_c0() const { return m >> SHIFTBITS_C0 & MASKBITS_C0; }

	float				get_f1() const { return get_c1() * (1.f / MASKBITS_C1); }
	float				get_f0() const { return get_c0() * (1.f / MASKBITS_C0); }

	void				setPacked(const INTEGRAL_T packed);
	INTEGRAL_T			getPacked()	const;

	void				set(const INTEGRAL_T s1,
							const INTEGRAL_T s0);

	Pixel2(const float f1,
		   const float f0);

	Pixel2(const INTEGRAL_T s1,
		   const INTEGRAL_T s0);

	Pixel2< INTEGRAL_T, NUMBITS_C1_T, NUMBITS_C0_T >&
	operator = (const Pixel2< INTEGRAL_T, NUMBITS_C1_T, NUMBITS_C0_T >& src);

	template < typename	S_INTEGRAL_T,
			   unsigned	S_NUMBITS_C1_T,
			   unsigned	S_NUMBITS_C0_T >
	void convert(const Pixel2< S_INTEGRAL_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src);

	template < typename	S_INTEGRAL_T,
			   unsigned	S_NUMBITS_C2_T,
			   unsigned	S_NUMBITS_C1_T,
			   unsigned	S_NUMBITS_C0_T >
	void convert(const Pixel3< S_INTEGRAL_T, S_NUMBITS_C2_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src);

	template < typename	S_INTEGRAL_T,
			   unsigned	S_NUMBITS_C3_T,
			   unsigned	S_NUMBITS_C2_T,
			   unsigned	S_NUMBITS_C1_T,
			   unsigned	S_NUMBITS_C0_T >
	void convert(const Pixel4< S_INTEGRAL_T, S_NUMBITS_C3_T, S_NUMBITS_C2_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src);
};


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
void
Pixel2< INTEGRAL_T, NUMBITS_C1_T, NUMBITS_C0_T >::setPacked(const INTEGRAL_T packed)
{
	m = m & ~MASK | packed;
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
INTEGRAL_T
Pixel2< INTEGRAL_T, NUMBITS_C1_T, NUMBITS_C0_T >::getPacked() const
{
	return m & MASK;
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
void
Pixel2< INTEGRAL_T, NUMBITS_C1_T, NUMBITS_C0_T >::set(
	const INTEGRAL_T s1,
	const INTEGRAL_T s0)
{
	setPacked((s1 & MASKBITS_C1) << SHIFTBITS_C1 |
			  (s0 & MASKBITS_C0) << SHIFTBITS_C0);
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
Pixel2< INTEGRAL_T, NUMBITS_C1_T, NUMBITS_C0_T >&
Pixel2< INTEGRAL_T, NUMBITS_C1_T, NUMBITS_C0_T >::operator =
	(const Pixel2< INTEGRAL_T, NUMBITS_C1_T, NUMBITS_C0_T >& src)
{
	setPacked(src.getPacked());

	return *this;
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
Pixel2< INTEGRAL_T, NUMBITS_C1_T, NUMBITS_C0_T >::Pixel2(
	const float f1,
	const float f0)
{
	set(toIntRound(f1 * MASKBITS_C1),
		toIntRound(f0 * MASKBITS_C0));
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
Pixel2< INTEGRAL_T, NUMBITS_C1_T, NUMBITS_C0_T >::Pixel2(
	const INTEGRAL_T s1,
	const INTEGRAL_T s0)
{
	set(s1, s0);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// class Pixel3
////////////////////////////////////////////////////////////////////////////////////////////////////

template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
class Pixel3
{
	INTEGRAL_T			m;

public:

	enum
	{
		NUMBITS_C2		= NUMBITS_C2_T,
		NUMBITS_C1		= NUMBITS_C1_T,
		NUMBITS_C0		= NUMBITS_C0_T,
		NUMBITS			= NUMBITS_C2_T + NUMBITS_C1_T + NUMBITS_C0_T,

		NUMBYTES		= NUMBITS + 7 >> 3,

		MASKBITS_C2		= (1 << NUMBITS_C2_T) - 1,
		MASKBITS_C1		= (1 << NUMBITS_C1_T) - 1,
		MASKBITS_C0		= (1 << NUMBITS_C0_T) - 1,

#if		REND_TARGET_ENDIANNESS == __TARGET_ENDIANNESS_BIG

		SHIFTBITS		= (sizeof(INTEGRAL_T) << 3) - NUMBITS,

		SHIFTBITS_C2	= SHIFTBITS,
		SHIFTBITS_C1	= SHIFTBITS + NUMBITS_C2,
		SHIFTBITS_C0	= SHIFTBITS + NUMBITS_C2 + NUMBITS_C1,
#else

		SHIFTBITS		= 0,

		SHIFTBITS_C2	= SHIFTBITS + NUMBITS_C0 + NUMBITS_C1,
		SHIFTBITS_C1	= SHIFTBITS + NUMBITS_C0,
		SHIFTBITS_C0	= SHIFTBITS,
#endif

		MASK			= (1 << NUMBITS) - 1 << SHIFTBITS,

		FORCE_INTEGRAL	= (INTEGRAL_T) -1
	};

	Pixel3() {}

	INTEGRAL_T			get_c2() const { return m >> SHIFTBITS_C2 & MASKBITS_C2; }
	INTEGRAL_T			get_c1() const { return m >> SHIFTBITS_C1 & MASKBITS_C1; }
	INTEGRAL_T			get_c0() const { return m >> SHIFTBITS_C0 & MASKBITS_C0; }

	float				get_f2() const { return get_c2() * (1.f / MASKBITS_C2); }
	float				get_f1() const { return get_c1() * (1.f / MASKBITS_C1); }
	float				get_f0() const { return get_c0() * (1.f / MASKBITS_C0); }

	void				setPacked(const INTEGRAL_T packed);
	INTEGRAL_T			getPacked()	const;

	void				set(const INTEGRAL_T s2,
							const INTEGRAL_T s1,
							const INTEGRAL_T s0);

	Pixel3(const float f2,
		   const float f1,
		   const float f0);

	Pixel3(const INTEGRAL_T s2,
		   const INTEGRAL_T s1,
		   const INTEGRAL_T s0);

	Pixel3< INTEGRAL_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >&
	operator = (const Pixel3< INTEGRAL_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >& src);

	template < typename	S_INTEGRAL_T,
			   unsigned	S_NUMBITS_C1_T,
			   unsigned	S_NUMBITS_C0_T >
	void convert(const Pixel2< S_INTEGRAL_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src);

	template < typename	S_INTEGRAL_T,
			   unsigned	S_NUMBITS_C2_T,
			   unsigned	S_NUMBITS_C1_T,
			   unsigned	S_NUMBITS_C0_T >
	void convert(const Pixel3< S_INTEGRAL_T, S_NUMBITS_C2_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src);

	template < typename	S_INTEGRAL_T,
			   unsigned	S_NUMBITS_C3_T,
			   unsigned	S_NUMBITS_C2_T,
			   unsigned	S_NUMBITS_C1_T,
			   unsigned	S_NUMBITS_C0_T >
	void convert(const Pixel4< S_INTEGRAL_T, S_NUMBITS_C3_T, S_NUMBITS_C2_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src);
};


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
void
Pixel3< INTEGRAL_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::setPacked(const INTEGRAL_T packed)
{
	m = m & ~MASK | packed;
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
INTEGRAL_T
Pixel3< INTEGRAL_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::getPacked() const
{
	return m & MASK;
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
void
Pixel3< INTEGRAL_T,	NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::set(
	const INTEGRAL_T s2,
	const INTEGRAL_T s1,
	const INTEGRAL_T s0)
{
	setPacked((s2 & MASKBITS_C2) << SHIFTBITS_C2 |
			  (s1 & MASKBITS_C1) << SHIFTBITS_C1 |
			  (s0 & MASKBITS_C0) << SHIFTBITS_C0);
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
Pixel3< INTEGRAL_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >&
Pixel3< INTEGRAL_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::operator =
	(const Pixel3< INTEGRAL_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >& src)
{
	setPacked(src.getPacked());

	return *this;
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
Pixel3< INTEGRAL_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::Pixel3(
	const float f2,
	const float f1,
	const float f0)
{
	set(toIntRound(f2 * MASKBITS_C2),
		toIntRound(f1 * MASKBITS_C1),
		toIntRound(f0 * MASKBITS_C0));
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
Pixel3< INTEGRAL_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::Pixel3(
	const INTEGRAL_T s2,
	const INTEGRAL_T s1,
	const INTEGRAL_T s0)
{
	set(s2, s1, s0);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// class Pixel4
////////////////////////////////////////////////////////////////////////////////////////////////////

template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C3_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
class Pixel4
{
	INTEGRAL_T			m;

public:

	enum
	{
		NUMBITS_C3		= NUMBITS_C3_T,
		NUMBITS_C2		= NUMBITS_C2_T,
		NUMBITS_C1		= NUMBITS_C1_T,
		NUMBITS_C0		= NUMBITS_C0_T,
		NUMBITS			= NUMBITS_C3_T + NUMBITS_C2_T + NUMBITS_C1_T + NUMBITS_C0_T,

		NUMBYTES		= NUMBITS + 7 >> 3,

		MASKBITS_C3		= (1 << NUMBITS_C3_T) - 1,
		MASKBITS_C2		= (1 << NUMBITS_C2_T) - 1,
		MASKBITS_C1		= (1 << NUMBITS_C1_T) - 1,
		MASKBITS_C0		= (1 << NUMBITS_C0_T) - 1,

#if		REND_TARGET_ENDIANNESS == __TARGET_ENDIANNESS_BIG

		SHIFTBITS		= (sizeof(INTEGRAL_T) << 3) - NUMBITS,

		SHIFTBITS_C3	= SHIFTBITS,
		SHIFTBITS_C2	= SHIFTBITS + NUMBITS_C3,
		SHIFTBITS_C1	= SHIFTBITS + NUMBITS_C3 + NUMBITS_C2,
		SHIFTBITS_C0	= SHIFTBITS + NUMBITS_C3 + NUMBITS_C2 + NUMBITS_C1,
#else

		SHIFTBITS		= 0,

		SHIFTBITS_C3	= SHIFTBITS + NUMBITS_C0 + NUMBITS_C1 + NUMBITS_C2,
		SHIFTBITS_C2	= SHIFTBITS + NUMBITS_C0 + NUMBITS_C1,
		SHIFTBITS_C1	= SHIFTBITS + NUMBITS_C0,
		SHIFTBITS_C0	= SHIFTBITS,
#endif

		MASK			= (1 << NUMBITS) - 1 << SHIFTBITS,

		FORCE_INTEGRAL	= (INTEGRAL_T) -1
	};

	Pixel4() {}

	INTEGRAL_T			get_c3() const { return m >> SHIFTBITS_C3 & MASKBITS_C3; }
	INTEGRAL_T			get_c2() const { return m >> SHIFTBITS_C2 & MASKBITS_C2; }
	INTEGRAL_T			get_c1() const { return m >> SHIFTBITS_C1 & MASKBITS_C1; }
	INTEGRAL_T			get_c0() const { return m >> SHIFTBITS_C0 & MASKBITS_C0; }

	float				get_f3() const { return get_c3() * (1.f / MASKBITS_C3); }
	float				get_f2() const { return get_c2() * (1.f / MASKBITS_C2); }
	float				get_f1() const { return get_c1() * (1.f / MASKBITS_C1); }
	float				get_f0() const { return get_c0() * (1.f / MASKBITS_C0); }

	void			setPacked(const INTEGRAL_T packed);
	INTEGRAL_T		getPacked() const;

	void			set(const INTEGRAL_T s3,
						const INTEGRAL_T s2,
						const INTEGRAL_T s1,
						const INTEGRAL_T s0);

	Pixel4(const float f3,
		   const float f2,
		   const float f1,
		   const float f0);

	Pixel4(const INTEGRAL_T s3,
		   const INTEGRAL_T s2,
		   const INTEGRAL_T s1,
		   const INTEGRAL_T s0);

	Pixel4< INTEGRAL_T, NUMBITS_C3_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >&
	operator = (const Pixel4< INTEGRAL_T, NUMBITS_C3_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >& src);

	template < typename	S_INTEGRAL_T,
			   unsigned	S_NUMBITS_C1_T,
			   unsigned	S_NUMBITS_C0_T >
	void convert(const Pixel2< S_INTEGRAL_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src);

	template < typename	S_INTEGRAL_T,
			   unsigned	S_NUMBITS_C2_T,
			   unsigned	S_NUMBITS_C1_T,
			   unsigned	S_NUMBITS_C0_T >
	void convert(const Pixel3< S_INTEGRAL_T, S_NUMBITS_C2_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src);

	template < typename	S_INTEGRAL_T,
			   unsigned	S_NUMBITS_C3_T,
			   unsigned	S_NUMBITS_C2_T,
			   unsigned	S_NUMBITS_C1_T,
			   unsigned	S_NUMBITS_C0_T >
	void convert(const Pixel4< S_INTEGRAL_T, S_NUMBITS_C3_T, S_NUMBITS_C2_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src);
};


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C3_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
void
Pixel4< INTEGRAL_T, NUMBITS_C3_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::setPacked(const INTEGRAL_T packed)
{
	m = m & ~MASK | packed;
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C3_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
INTEGRAL_T
Pixel4< INTEGRAL_T, NUMBITS_C3_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::getPacked() const
{
	return m & MASK;
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C3_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
void
Pixel4< INTEGRAL_T, NUMBITS_C3_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::set(
	const INTEGRAL_T s3,
	const INTEGRAL_T s2,
	const INTEGRAL_T s1,
	const INTEGRAL_T s0)
{
	setPacked((s3 & MASKBITS_C3) << SHIFTBITS_C3 |
			  (s2 & MASKBITS_C2) << SHIFTBITS_C2 |
			  (s1 & MASKBITS_C1) << SHIFTBITS_C1 |
			  (s0 & MASKBITS_C0) << SHIFTBITS_C0);
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C3_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
Pixel4< INTEGRAL_T, NUMBITS_C3_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >&
Pixel4< INTEGRAL_T, NUMBITS_C3_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::operator =
	(const Pixel4< INTEGRAL_T, NUMBITS_C3_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >& src)
{
	setPacked(src.getPacked());

	return *this;
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C3_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
Pixel4< INTEGRAL_T, NUMBITS_C3_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::Pixel4(
	const float f3,
	const float f2,
	const float f1,
	const float f0)
{
	set(toIntRound(f3 * MASKBITS_C3),
		toIntRound(f2 * MASKBITS_C2),
		toIntRound(f1 * MASKBITS_C1),
		toIntRound(f0 * MASKBITS_C0));
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C3_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
Pixel4< INTEGRAL_T, NUMBITS_C3_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::Pixel4(
	const INTEGRAL_T s3,
	const INTEGRAL_T s2,
	const INTEGRAL_T s1,
	const INTEGRAL_T s0)
{
	set(s3, s2, s1, s0);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Pixel2 converters
////////////////////////////////////////////////////////////////////////////////////////////////////

template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
template < typename	S_INTEGRAL_T,
		   unsigned	S_NUMBITS_C1_T,
		   unsigned	S_NUMBITS_C0_T >

void Pixel2< INTEGRAL_T, NUMBITS_C1_T, NUMBITS_C0_T >::
	convert(const Pixel2< S_INTEGRAL_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src)
{
	const int32 x1 = toIntRound(src.get_c1() * (MASKBITS_C1 / float(src.MASKBITS_C1)));
	const int32 x0 = toIntRound(src.get_c0() * (MASKBITS_C0 / float(src.MASKBITS_C0)));

	set(static_cast< INTEGRAL_T >(x1),
		static_cast< INTEGRAL_T >(x0));
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
template < typename	S_INTEGRAL_T,
		   unsigned	S_NUMBITS_C2_T,
		   unsigned	S_NUMBITS_C1_T,
		   unsigned	S_NUMBITS_C0_T >

void Pixel2< INTEGRAL_T, NUMBITS_C1_T, NUMBITS_C0_T >::
	convert(const Pixel3< S_INTEGRAL_T, S_NUMBITS_C2_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src)
{
	const int32 x1 = toIntRound(src.get_c1() * (MASKBITS_C1 / float(src.MASKBITS_C1)));
	const int32 x0 = toIntRound(src.get_c0() * (MASKBITS_C0 / float(src.MASKBITS_C0)));

	set(static_cast< INTEGRAL_T >(x1),
		static_cast< INTEGRAL_T >(x0));
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
template < typename	S_INTEGRAL_T,
		   unsigned	S_NUMBITS_C3_T,
		   unsigned	S_NUMBITS_C2_T,
		   unsigned	S_NUMBITS_C1_T,
		   unsigned	S_NUMBITS_C0_T >

void Pixel2< INTEGRAL_T, NUMBITS_C1_T, NUMBITS_C0_T >::
	convert(const Pixel4< S_INTEGRAL_T, S_NUMBITS_C3_T, S_NUMBITS_C2_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src)
{
	const int32 x1 = toIntRound(src.get_c1() * (MASKBITS_C1 / float(src.MASKBITS_C1)));
	const int32 x0 = toIntRound(src.get_c0() * (MASKBITS_C0 / float(src.MASKBITS_C0)));

	set(static_cast< INTEGRAL_T >(x1),
		static_cast< INTEGRAL_T >(x0));
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Pixel3 converters
////////////////////////////////////////////////////////////////////////////////////////////////////

template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
template < typename	S_INTEGRAL_T,
		   unsigned	S_NUMBITS_C1_T,
		   unsigned	S_NUMBITS_C0_T >

void Pixel3< INTEGRAL_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::
		convert(const Pixel2< S_INTEGRAL_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src)
{
	const int32 x2 = MASKBITS_C2;
	const int32 x1 = toIntRound(src.get_c1() * (MASKBITS_C1 / float(src.MASKBITS_C1)));
	const int32 x0 = toIntRound(src.get_c0() * (MASKBITS_C0 / float(src.MASKBITS_C0)));

	set(static_cast< INTEGRAL_T >(x2),
		static_cast< INTEGRAL_T >(x1),
		static_cast< INTEGRAL_T >(x0));
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
template < typename	S_INTEGRAL_T,
		   unsigned	S_NUMBITS_C2_T,
		   unsigned	S_NUMBITS_C1_T,
		   unsigned	S_NUMBITS_C0_T >

void Pixel3< INTEGRAL_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::
		convert(const Pixel3< S_INTEGRAL_T, S_NUMBITS_C2_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src)
{
	const int32 x2 = toIntRound(src.get_c2() * (MASKBITS_C2 / float(src.MASKBITS_C2)));
	const int32 x1 = toIntRound(src.get_c1() * (MASKBITS_C1 / float(src.MASKBITS_C1)));
	const int32 x0 = toIntRound(src.get_c0() * (MASKBITS_C0 / float(src.MASKBITS_C0)));

	set(static_cast< INTEGRAL_T >(x2),
		static_cast< INTEGRAL_T >(x1),
		static_cast< INTEGRAL_T >(x0));
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
template < typename	S_INTEGRAL_T,
		   unsigned	S_NUMBITS_C3_T,
		   unsigned	S_NUMBITS_C2_T,
		   unsigned	S_NUMBITS_C1_T,
		   unsigned	S_NUMBITS_C0_T >

void Pixel3< INTEGRAL_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::
		convert(const Pixel4< S_INTEGRAL_T, S_NUMBITS_C3_T, S_NUMBITS_C2_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src)
{
	const int32 x2 = toIntRound(src.get_c2() * (MASKBITS_C2 / float(src.MASKBITS_C2)));
	const int32 x1 = toIntRound(src.get_c1() * (MASKBITS_C1 / float(src.MASKBITS_C1)));
	const int32 x0 = toIntRound(src.get_c0() * (MASKBITS_C0 / float(src.MASKBITS_C0)));

	set(static_cast< INTEGRAL_T >(x2),
		static_cast< INTEGRAL_T >(x1),
		static_cast< INTEGRAL_T >(x0));
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Pixel4 converters
////////////////////////////////////////////////////////////////////////////////////////////////////

template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C3_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
template < typename	S_INTEGRAL_T,
		   unsigned	S_NUMBITS_C1_T,
		   unsigned	S_NUMBITS_C0_T >

void Pixel4< INTEGRAL_T, NUMBITS_C3_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::
		convert(const Pixel2< S_INTEGRAL_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src)
{
	const int32 x3 = MASKBITS_C3;
	const int32 x2 = MASKBITS_C2;
	const int32 x1 = toIntRound(src.get_c1() * (MASKBITS_C1 / float(src.MASKBITS_C1)));
	const int32 x0 = toIntRound(src.get_c0() * (MASKBITS_C0 / float(src.MASKBITS_C0)));

	set(static_cast< INTEGRAL_T >(x3),
		static_cast< INTEGRAL_T >(x2),
		static_cast< INTEGRAL_T >(x1),
		static_cast< INTEGRAL_T >(x0));
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C3_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
template < typename	S_INTEGRAL_T,
		   unsigned	S_NUMBITS_C2_T,
		   unsigned	S_NUMBITS_C1_T,
		   unsigned	S_NUMBITS_C0_T >

void Pixel4< INTEGRAL_T, NUMBITS_C3_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::
		convert(const Pixel3< S_INTEGRAL_T, S_NUMBITS_C2_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src)
{
	const int32 x3 = MASKBITS_C3;
	const int32 x2 = toIntRound(src.get_c2() * (MASKBITS_C2 / float(src.MASKBITS_C2)));
	const int32 x1 = toIntRound(src.get_c1() * (MASKBITS_C1 / float(src.MASKBITS_C1)));
	const int32 x0 = toIntRound(src.get_c0() * (MASKBITS_C0 / float(src.MASKBITS_C0)));

	set(static_cast< INTEGRAL_T >(x3),
		static_cast< INTEGRAL_T >(x2),
		static_cast< INTEGRAL_T >(x1),
		static_cast< INTEGRAL_T >(x0));
}


template < typename	INTEGRAL_T,
		   unsigned	NUMBITS_C3_T,
		   unsigned	NUMBITS_C2_T,
		   unsigned	NUMBITS_C1_T,
		   unsigned	NUMBITS_C0_T >
template < typename	S_INTEGRAL_T,
		   unsigned	S_NUMBITS_C3_T,
		   unsigned	S_NUMBITS_C2_T,
		   unsigned	S_NUMBITS_C1_T,
		   unsigned	S_NUMBITS_C0_T >

void Pixel4< INTEGRAL_T, NUMBITS_C3_T, NUMBITS_C2_T, NUMBITS_C1_T, NUMBITS_C0_T >::
		convert(const Pixel4< S_INTEGRAL_T, S_NUMBITS_C3_T, S_NUMBITS_C2_T, S_NUMBITS_C1_T, S_NUMBITS_C0_T >& src)
{
	const int32 x3 = toIntRound(src.get_c3() * (MASKBITS_C3 / float(src.MASKBITS_C3)));
	const int32 x2 = toIntRound(src.get_c2() * (MASKBITS_C2 / float(src.MASKBITS_C2)));
	const int32 x1 = toIntRound(src.get_c1() * (MASKBITS_C1 / float(src.MASKBITS_C1)));
	const int32 x0 = toIntRound(src.get_c0() * (MASKBITS_C0 / float(src.MASKBITS_C0)));

	set(static_cast< INTEGRAL_T >(x3),
		static_cast< INTEGRAL_T >(x2),
		static_cast< INTEGRAL_T >(x1),
		static_cast< INTEGRAL_T >(x0));
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// common pixel specializations
////////////////////////////////////////////////////////////////////////////////////////////////////

typedef Pixel4< uint16, 1,	5,	5,	5 >		PixelARGB1555;
typedef Pixel4< uint32, 8,	8,	8,	8 >		PixelARGB8888;

typedef Pixel3< uint16, 5,	6,	5 >			PixelRGB565;
typedef Pixel3< uint32, 8,	8,	8 >			PixelRGB888;

////////////////////////////////////////////////////////////////////////////////////////////////////
// remark on performance optimisations
//
// although we use 16-bit integral types for the hi-color common pixel formats an integral of native
// 32-bit width could perform better on some CPUs; applications defining their own pixel
// specializations should consider this for best performance.
////////////////////////////////////////////////////////////////////////////////////////////////////

} // namespace rend

#endif // __pixel_H__
